package org.springblade.thingsphere.utils;

import lombok.extern.slf4j.Slf4j;
import org.springblade.thingsphere.CompositeProtocolSupport;
import org.springblade.thingsphere.ProtocolSupportProvider;
import org.springblade.thingsphere.message.DeviceMessageCodec;
import org.springblade.thingsphere.network.protocol.ProtocolClassLoader;
import org.springblade.thingsphere.network.protocol.ProtocolSupportDefinition;
import org.springblade.thingsphere.type.DefaultTransport;

import java.io.File;
import java.net.URL;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lhb
 * @date 2024/9/25 下午5:20
 */
@Slf4j
public class DynamicLoading {

	public static void main(String[] args) throws Exception {
		DynamicLoading dynamicLoading = new DynamicLoading();
		ProtocolSupportDefinition protocolSupportDefinition = new ProtocolSupportDefinition();
		protocolSupportDefinition.setId(1L);
		protocolSupportDefinition.setName("IOT");
		protocolSupportDefinition.setClazzName("org.thingsphere.protocol.IotProtocolSupportProvider");
		protocolSupportDefinition.setJarPath("D:\\Coding\\WorkSpace-Job\\shenrui\\saas\\thingsphere-protocol\\target\\thingsphere-protocol-0.0.1-SNAPSHOT.jar");

		CompositeProtocolSupport load = dynamicLoading.load(protocolSupportDefinition);

		DeviceMessageCodec deviceMessageCodec = load.getMessageCodecSupports().get(DefaultTransport.MQTT.getId());
		deviceMessageCodec.decoder("你好");
		deviceMessageCodec.encode("hello");
	}

	private final Map<Long, ProtocolClassLoader> protocolLoaders = new ConcurrentHashMap<>();
	private final Map<String, ProtocolSupportProvider> loaded = new ConcurrentHashMap<>();

	/**
	 * 动态加载jar
	 *
	 * @param definition
	 * @return
	 */
	public CompositeProtocolSupport load(ProtocolSupportDefinition definition) {
		try {
			String location = definition.getJarPath();
			String provider = definition.getClazzName();
			URL url;
			if (!location.contains("://")) {
				url = (new File(location)).toURI().toURL();
			} else {
				url = new URL("jar:" + location + "!/");
			}

			URL fLocation = url;
			ProtocolSupportProvider supportProvider = (ProtocolSupportProvider) this.loaded.remove(provider);
			if (null != supportProvider) {
				supportProvider.dispose();
			}

			ProtocolClassLoader loader = (ProtocolClassLoader) this.protocolLoaders.compute(definition.getId(), (key, old) -> {
				if (null != old) {
					try {
						this.closeLoader(old);
					} catch (Exception var5) {
						log.error("加载jar包失败", var5);
					}
				}
				return this.createClassLoader(fLocation);
			});

			log.debug("load protocol support from : {}", location);
			if (provider != null) {
				supportProvider = (ProtocolSupportProvider) Class.forName(provider, true, loader).newInstance();
			} else {
				supportProvider = (ProtocolSupportProvider) ServiceLoader.load(ProtocolSupportProvider.class, loader).iterator().next();
			}
			ProtocolSupportProvider oldProvider = (ProtocolSupportProvider) this.loaded.put(provider, supportProvider);

			try {
				if (null != oldProvider) {
					oldProvider.dispose();
				}
			} catch (Exception var11) {
				log.error(var11.getMessage(), var11);
			}
			// 调用协议包中的创建
			return supportProvider.create();
		} catch (Throwable var12) {
		}
		return null;
	}

	protected void closeLoader(ProtocolClassLoader loader) {
		try {
			loader.close();
		} catch (Throwable var3) {
			throw new RuntimeException(var3);
		}
	}

	protected ProtocolClassLoader createClassLoader(URL location) {
		return new ProtocolClassLoader(new URL[]{location}, this.getClass().getClassLoader());
	}

}
